package com.lb.pdm.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.lb.pdm.common.constants.RedisConstants;
import com.lb.pdm.common.result.GraceJSONResult;
import com.lb.pdm.entity.*;
import com.lb.pdm.entity.bo.ApprovalBO;
import com.lb.pdm.entity.bo.HouseholdTransferApplicationBO;
import com.lb.pdm.entity.bo.HouseholdTransferBO;
import com.lb.pdm.entity.vo.HouseholdTransferVO;
import com.lb.pdm.mapper.HouseholdInfoMapper;
import com.lb.pdm.mapper.HouseholdMemberMapper;
import com.lb.pdm.mapper.HouseholdTransferMapper;
import com.lb.pdm.mapper.PersonInfoMapper;
import com.lb.pdm.service.HouseholdTransferService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 户口迁移表 服务实现类
 * </p>
 *
 * @author pdm
 * @since 2025-10-29
 */
@Service
public class HouseholdTransferServiceImpl extends ServiceImpl<HouseholdTransferMapper, HouseholdTransfer> implements HouseholdTransferService {
    @Autowired
    private HouseholdTransferMapper householdTransferMapper;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private HouseholdInfoMapper householdInfoMapper;
    @Autowired
    private HouseholdMemberMapper  householdMemberMapper;
    @Autowired
    private PersonInfoMapper personInfoMapper;

    @Override
    public List<HouseholdTransferVO> getHouseholdTransfer(HouseholdTransferBO householdTransferBO) {
        String name = householdTransferBO.getName();
        String idCard = householdTransferBO.getIdCard();
        Byte status = householdTransferBO.getApplicationStatus();
        int start = (householdTransferBO.getPageNum() - 1) * householdTransferBO.getPageSize();
        Integer pageSize = householdTransferBO.getPageSize();
        return householdTransferMapper.listHouseholdTransferVO(name, idCard, status, start, pageSize);
    }

    @Override
    public HouseholdTransferVO getHouseholdTransferDetail(Long id) {
        return householdTransferMapper.getHouseholdTransferDetail(id);
    }

    @Override
    @Transactional
    public int updateHouseholdTransfer(ApprovalBO approvalBO, String token) {
        Long transferId = approvalBO.getTransferId();
        Byte applicationStatus = approvalBO.getApplicationStatus();
        String approvalRemark = approvalBO.getApprovalRemark();

        String sysUserString  =  redisTemplate.opsForValue().get(RedisConstants.USER_TOKEN_PREFIX + token);
        SysUser sysUser = JSON.parseObject(sysUserString, SysUser.class);

        UpdateWrapper<HouseholdTransfer> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", transferId)
                .set("application_status", applicationStatus)
                .set("approval_remark", approvalRemark)
                .set("approval_time", LocalDateTime.now())
                .set("approval_by", sysUser.getId())
                .set("update_time", LocalDateTime.now())
                .set("update_by", sysUser.getId());

        householdTransfer(transferId);

        return householdTransferMapper.update(null, updateWrapper);
    }

    @Override
    @Transactional
    public GraceJSONResult householdTransfer(Long id) {
        LambdaQueryWrapper<HouseholdTransfer> householdTransferQuery = new LambdaQueryWrapper<>();
        householdTransferQuery.eq(HouseholdTransfer::getId, id);
        HouseholdTransfer householdTransfer = householdTransferMapper.selectOne(householdTransferQuery);

        Long originalHouseholdId = householdTransfer.getOriginalHouseholdId();
        Long targetHouseholdId = householdTransfer.getTargetHouseholdId();
        Long personId = householdTransfer.getPersonId();

        // 原户籍id不为null
        // 可能是夫妻投靠、子女投靠父母
        // 需要把迁移成员的原户籍中的状态改为已迁出
        if (originalHouseholdId != null) {
            // 查询原户籍
            LambdaQueryWrapper<HouseholdInfo> householdInfoQuery = new LambdaQueryWrapper<>();
            householdInfoQuery.eq(HouseholdInfo::getId, originalHouseholdId);
            HouseholdInfo householdInfo = householdInfoMapper.selectOne(householdInfoQuery);
            // 获取原户籍的户主id
            Long householderId = householdInfo.getHouseholderId();


            // 判断原户籍的户主id是否与迁移人员id一致
            // 不一致的话，只需在原户籍将该成员的状态改为已迁出即可
            // 一致的话，需要看看原户籍还有没有别人
            if (Objects.equals(householderId, personId)) {
                LambdaQueryWrapper<HouseholdMember> householdMemberQuery = new LambdaQueryWrapper<>();
                householdMemberQuery.eq(HouseholdMember::getHouseholdId, originalHouseholdId)
                        .eq(HouseholdMember::getStatus, 1);
                List<HouseholdMember> householdMembers = householdMemberMapper.selectList(householdMemberQuery);

                // 如果没有别人，则将原户籍注销即可，然后迁移人员在household_member表中的status字段改为已迁出
                if (householdMembers.size() == 1) { // 原户籍只有迁移人员这一个成员
                    LambdaUpdateWrapper<HouseholdInfo> householdInfoUpdateWrapper = new LambdaUpdateWrapper<>();
                    householdInfoUpdateWrapper.eq(HouseholdInfo::getId, originalHouseholdId)
                            .set(HouseholdInfo::getStatus, (byte)0);
                    int i = householdInfoMapper.update(null, householdInfoUpdateWrapper);
                    if (i <= 0) {
                        return GraceJSONResult.errorMsg("注销成员原户籍失败");
                    }

                }else {
                    // 如果还有别人，需要重新指定户主，然后迁移人员在household_member表中的status字段改为已迁出
                    Long newHouseholderId = selectNewHouseholder(householdMembers, personId);

                    if (newHouseholderId == null) {
                        return GraceJSONResult.errorMsg("无法选择合适的新户主，请人工处理");
                    }

                    // 更新户籍信息，指定新户主
                    LambdaUpdateWrapper<HouseholdInfo> householdInfoUpdateWrapper = new LambdaUpdateWrapper<>();
                    householdInfoUpdateWrapper.eq(HouseholdInfo::getId, originalHouseholdId)
                            .set(HouseholdInfo::getHouseholderId, newHouseholderId);
                    int updateResult = householdInfoMapper.update(null, householdInfoUpdateWrapper);
                    if (updateResult <= 0) {
                        return GraceJSONResult.errorMsg("更新户主信息失败");
                    }

                }
            }

            // 将迁移人员在household_member表中的status字段改为已迁出
            LambdaQueryWrapper<HouseholdMember> householdMemberQuery = new LambdaQueryWrapper<>();
            householdMemberQuery.eq(HouseholdMember::getPersonId, personId);
            HouseholdMember householdMember = householdMemberMapper.selectOne(householdMemberQuery);
            householdMember.setStatus((byte)0);

            UpdateWrapper<HouseholdMember> householdMemberUpdateWrapper = new UpdateWrapper<>();
            householdMemberUpdateWrapper.eq("id", householdMember.getId());
            int i = householdMemberMapper.update(householdMember, householdMemberUpdateWrapper);

            if (i <= 0) {
                return GraceJSONResult.errorMsg("更新成员原户籍状态失败");
            }
        }

        // 旧户籍信息更新完毕后，需要在新户籍里插入成员信息
        HouseholdMember newHouseholdMember = new HouseholdMember();
        newHouseholdMember.setHouseholdId(targetHouseholdId);
        newHouseholdMember.setPersonId(personId);
        newHouseholdMember.setRelationship(householdTransfer.getRelationship());
        newHouseholdMember.setJoinDate(new Date());
        newHouseholdMember.setJoinReason(householdTransfer.getTransferReason());
        newHouseholdMember.setStatus((byte)1);
        newHouseholdMember.setCreateTime(new Date());
        newHouseholdMember.setUpdateTime(new Date());
        int newHouseholdMemberInsertRes = householdMemberMapper.insert(newHouseholdMember);

        if (newHouseholdMemberInsertRes <= 0) {
            return GraceJSONResult.errorMsg("插入成员新户籍失败");
        }

        return GraceJSONResult.ok();
    }

    @Override
    public GraceJSONResult applyTransfer(HouseholdTransferApplicationBO householdTransferApplicationBO,
                                         String token) {
        String applicantIdCard = householdTransferApplicationBO.getApplicantIdCard();
        String targetIdCard = householdTransferApplicationBO.getTargetIdCard();
        String relationship = householdTransferApplicationBO.getRelationship();
        String transferReason = householdTransferApplicationBO.getTransferReason();

        HouseholdTransfer householdTransfer = new HouseholdTransfer();
        BeanUtils.copyProperties(householdTransferApplicationBO, householdTransfer);

        LambdaQueryWrapper<PersonInfo> personInfoQuery1 = new LambdaQueryWrapper<>();
        personInfoQuery1.eq(PersonInfo::getIdCard, applicantIdCard);
        PersonInfo applicant = personInfoMapper.selectOne(personInfoQuery1);
        householdTransfer.setPersonId(applicant.getId());

        LambdaQueryWrapper<PersonInfo> personInfoQuery2 = new LambdaQueryWrapper<>();
        personInfoQuery2.eq(PersonInfo::getIdCard, targetIdCard);
        PersonInfo targetPerson = personInfoMapper.selectOne(personInfoQuery2);

        LambdaQueryWrapper<HouseholdMember> householdMemberQuery1 = new LambdaQueryWrapper<>();
        householdMemberQuery1.eq(HouseholdMember::getPersonId, applicant.getId());
        HouseholdMember householdMember1 = householdMemberMapper.selectOne(householdMemberQuery1);
        Long originalHouseholdId = householdMember1.getHouseholdId();

        LambdaQueryWrapper<HouseholdMember> householdMemberQuery2 = new LambdaQueryWrapper<>();
        householdMemberQuery2.eq(HouseholdMember::getPersonId, targetPerson.getId());
        HouseholdMember householdMember2 = householdMemberMapper.selectOne(householdMemberQuery2);
        Long targetHouseholdId = householdMember2.getHouseholdId();

        LambdaQueryWrapper<HouseholdInfo> householdInfoQuery = new LambdaQueryWrapper<>();
        householdInfoQuery.eq(HouseholdInfo::getId, targetHouseholdId);
        HouseholdInfo householdInfo = householdInfoMapper.selectOne(householdInfoQuery);
        if (!Objects.equals(householdInfo.getHouseholderId(), targetPerson.getId())) {
            return GraceJSONResult.errorMsg("被投靠人不是户主");
        }
        
        householdTransfer.setOriginalHouseholdId(originalHouseholdId);
        householdTransfer.setTargetHouseholdId(targetHouseholdId);
        householdTransfer.setApplicationDate(new Date());
        householdTransfer.setApplicationStatus((byte)1);
        householdTransfer.setCreateTime(new Date());
        householdTransfer.setUpdateTime(new Date());

        String sysUserString = redisTemplate.opsForValue().get(RedisConstants.USER_TOKEN_PREFIX + token);
        SysUser sysUser = JSON.parseObject(sysUserString, SysUser.class);
        householdTransfer.setCreateBy(sysUser.getId());
        householdTransfer.setUpdateBy(sysUser.getId());

        int insertRes = householdTransferMapper.insert(householdTransfer);

        if (insertRes <= 0) {
            return GraceJSONResult.errorMsg("申请户口迁移失败");
        }

        return GraceJSONResult.ok();
    }

    /**
     * 选择新户主
     * 选择规则：
     * 1. 优先选择成年人（年龄≥18岁）
     * 2. 在成年人中选择年龄最大的
     * 3. 如果都是未成年人，选择年龄最大的未成年人
     * 4. 如果年龄相同，按加入户籍时间优先（joinDate最早的）
     *
     * @param householdMembers 户籍成员列表
     * @param excludePersonId 需要排除的人员ID（即将迁出的户主）
     * @return 新户主的人员ID，如果无法选择则返回null
     */
    private Long selectNewHouseholder(List<HouseholdMember> householdMembers, Long excludePersonId) {
        // 过滤掉即将迁出的户主，只保留在册成员
        List<HouseholdMember> availableMembers = householdMembers.stream()
                .filter(member -> !Objects.equals(member.getPersonId(), excludePersonId))
                .filter(member -> member.getStatus() == 1) // 只考虑在册成员
                .collect(Collectors.toList());

        if (availableMembers.isEmpty()) {
            return null;
        }

        // 获取所有候选成员的详细信息
        List<Long> personIds = availableMembers.stream()
                .map(HouseholdMember::getPersonId)
                .collect(Collectors.toList());

        LambdaQueryWrapper<PersonInfo> personQuery = new LambdaQueryWrapper<>();
        personQuery.in(PersonInfo::getId, personIds)
                .eq(PersonInfo::getStatus, 1); // 只查询正常状态的人员
        List<PersonInfo> persons = personInfoMapper.selectList(personQuery);

        if (persons.isEmpty()) {
            return null;
        }

        // 创建候选人信息列表，包含成员信息和个人信息
        List<HouseholderCandidate> candidates = new ArrayList<>();
        for (HouseholdMember member : availableMembers) {
            PersonInfo person = persons.stream()
                    .filter(p -> Objects.equals(p.getId(), member.getPersonId()))
                    .findFirst()
                    .orElse(null);

            if (person != null && person.getBirthDate() != null) {
                int age = calculateAge(person.getBirthDate());
                candidates.add(new HouseholderCandidate(member, person, age));
            }
        }

        if (candidates.isEmpty()) {
            return null;
        }

        // 按照选择规则排序
        candidates.sort((c1, c2) -> {
            // 1. 优先选择成年人
            boolean c1IsAdult = c1.age >= 18;
            boolean c2IsAdult = c2.age >= 18;

            if (c1IsAdult && !c2IsAdult) {
                return -1; // c1优先
            }
            if (!c1IsAdult && c2IsAdult) {
                return 1; // c2优先
            }

            // 2. 年龄大的优先
            if (c1.age != c2.age) {
                return Integer.compare(c2.age, c1.age); // 降序，年龄大的在前
            }

            // 3. 年龄相同时，按加入户籍时间优先（joinDate最早的）
            Date joinDate1 = c1.member.getJoinDate();
            Date joinDate2 = c2.member.getJoinDate();

            if (joinDate1 != null && joinDate2 != null) {
                return joinDate1.compareTo(joinDate2); // 升序，时间早的在前
            }

            // 4. 如果加入时间也相同或为空，按人员ID排序（保证结果的确定性）
            return Long.compare(c1.person.getId(), c2.person.getId());
        });

        // 返回排序后的第一个候选人
        HouseholderCandidate selectedCandidate = candidates.get(0);

        // 记录选择结果（可以用于日志或审计）
        String selectionReason = buildSelectionReason(selectedCandidate, candidates);
        System.out.println("选择新户主: " + selectedCandidate.person.getName() +
                " (ID: " + selectedCandidate.person.getId() + "), 原因: " + selectionReason);

        return selectedCandidate.person.getId();
    }

    /**
     * 计算年龄
     * @param birthDate 出生日期
     * @return 年龄
     */
    private int calculateAge(Date birthDate) {
        if (birthDate == null) {
            return 0;
        }

        Calendar birth = Calendar.getInstance();
        birth.setTime(birthDate);

        Calendar now = Calendar.getInstance();

        int age = now.get(Calendar.YEAR) - birth.get(Calendar.YEAR);

        // 检查是否还没到生日
        if (now.get(Calendar.DAY_OF_YEAR) < birth.get(Calendar.DAY_OF_YEAR)) {
            age--;
        }

        return Math.max(0, age); // 确保年龄不为负数
    }

    /**
     * 构建选择原因说明
     * @param selected 被选中的候选人
     * @param allCandidates 所有候选人
     * @return 选择原因
     */
    private String buildSelectionReason(HouseholderCandidate selected, List<HouseholderCandidate> allCandidates) {
        StringBuilder reason = new StringBuilder();

        boolean hasAdults = allCandidates.stream().anyMatch(c -> c.age >= 18);
        boolean selectedIsAdult = selected.age >= 18;

        if (hasAdults && selectedIsAdult) {
            reason.append("成年人优先");
        } else if (!hasAdults) {
            reason.append("所有成员均为未成年人");
        }

        long sameAgeCount = allCandidates.stream()
                .filter(c -> c.age == selected.age)
                .filter(c -> selectedIsAdult == (c.age >= 18)) // 同样是成年人或未成年人
                .count();

        if (sameAgeCount > 1) {
            reason.append(", 同龄者中按加入时间优先");
        } else {
            reason.append(", 年龄最大(").append(selected.age).append("岁)");
        }

        return reason.toString();
    }

}

class HouseholderCandidate {
    final HouseholdMember member;
    final PersonInfo person;
    final int age;

    HouseholderCandidate(HouseholdMember member, PersonInfo person, int age) {
        this.member = member;
        this.person = person;
        this.age = age;
    }
}
